(function($){
	var jQuery = $;
	
	/**
	 * 销毁验证对象
	 */
	function destroy(el){
		var _el = $(el);
		var _box = _el.data("checkbox");
		if(_box){
			_box.checking = false;
			var _tip = _box.tip;
			if(_tip) _tip.remove();
		}
		_el.unbind().remove();
	}
	/**
	 * 绑定事件
	 */
	function bindEvent(el){
		var _el = $(el);
		var _box = _el.data("checkbox");
		_el.unbind(".checkbox");
		_el.bind("focus.checkbox", function(){
			_box.checking = false;
			if(_el.hasClass("checkbox_invalid"))
				createTip(el);
		}).bind("blur.checkbox", function(){
			_box.checking = true;
			exec(el);
		}).bind("mouseenter.checkbox", function(){
			if(_el.hasClass("checkbox_invalid"))
				createTip(el);
		}).bind("mouseleave.checkbox", function(){
			destroyTip(el);
		});
	}
	/**
	 * 创建显示验证提示框
	 */
	function createTip(el){
		var _el = $(el);
		var _box = _el.data("checkbox");
		var msg = _box.message;
		var opt = _box.options;
		var _tip = _box.tip;
		if(!_tip)
			_tip = _el.data("checkbox").tip = $("<div class=\"checkbox_tip\"><span class=\"checkbox_tip_content\"></span><span class=\"checkbox_tip_pointer\"></span></div>").appendTo("body");
		var _msg = _tip.find(".checkbox_tip_content").html(msg);
		//默认提示框为右侧，但是可以配置为下方，如果右侧宽度不够，则显示为下方
		var tip_site = opt.tipSite;
		_tip.fadeIn(100);
		if(document.body.clientWidth < (_el.offset().left + _el.outerWidth() + _msg.outerWidth() + 20)) tip_site = "bottom";
		if(tip_site == "bottom"){
			_tip.find(".checkbox_tip_pointer").removeClass("checkbox_tip_pointer").addClass("checkbox_tip_pointer_top");
			_msg.css({top:9, left:0});
			_tip.css({left:_el.offset().left, top:_el.offset().top+_el.outerHeight()});
		}else{
			_tip.find(".checkbox_tip_pointer_top").removeClass("checkbox_tip_pointer_top").addClass("checkbox_tip_pointer");
			_msg.css({top:0, left:10});
			_tip.css({left:_el.offset().left+_el.outerWidth(), top:_el.offset().top});
		}
	}
	/**
	 * 销毁验证提示框
	 */
	function destroyTip(el){
		if($(el).data("checkbox")){
			var _tip = $(el).data("checkbox").tip;
			if(_tip){
				_tip.fadeOut(100, function(){
					_tip.remove();
				});
				$(el).data("checkbox").tip = null;
			}
		}
	}
	/**
	 * 执行验证
	 */
	function exec(el){
		var _el = $(el), _box, opt, _tip, value;
		_box = _el.data("checkbox");
		/**
		 * 如果el无法获取配置信息则认为验证通过
		 */
		if(!_box) return true;
		opt = _box.options;
		/**
		 * 如果对象是不可见且配置不阻止隐藏的则验证通过
		 */
		if(_el.is(":hidden") && (!opt || !opt.preventHidden)) return true;
		_tip = _box.tip;
		value = _el.val();
		if(_el.attr("disabled") == true || _el.attr("disabled") == "true" || _el.attr("disabled") == "disabled")
			return true;
		if(opt.required){
			if(value == "" || !_el.is(":password") && jQuery.trim(value)==""){
				_el.addClass("checkbox_invalid");
				_box.message = opt.missingMessage;
				//createTip(el);
				return false;
			}
		}
		if(opt.validType){
			var validTypes = opt.validType.split("&&"), type, rule, param, result, dynaMsg, msg;
			for(var i=0,len=validTypes.length;i<len;i++){
				if(validTypes[i]==="") continue;
				type = /([a-zA-Z_]+)(.*)/.exec(validTypes[i]);
				rule = opt.rules[type[1]];
				if((value && rule) || rule.isNull){
					param = type[2]?JSON.parse(type[2]):[];
					result = rule["validator"].call(el, value, param);
					dynaMsg = undefined;
					if(typeof(result)==typeof({})){
						dynaMsg = result.msg;
						result = result.b;
					}
					if(!result){
						_el.addClass("checkbox_invalid");
						msg = rule["message"];
						if(param){
							for(var j=0,jlen=param.length;j<jlen;j++){
								msg = msg.replace(new RegExp("\\{"+j+"\\}", "g"), param[j]);
							}
						}
						_box.message = dynaMsg || opt.invalidMessage || msg;
						//createTip(el);
						return false;
					}
				}
			}
		}
		_el.removeClass("checkbox_invalid");
		destroyTip(el);
		return true;
	}
	$.fn.checkbox = function(opt, param){
		if(typeof(opt) == "string")
			return $.fn.checkbox.methods[opt](this, param);
		opt = opt || {};
		return this.each(function(){
			var _box = $(this).data("checkbox");
			if(_box){
				jQuery.extend(_box.options, opt);
			}else{
				$(this).data("checkbox", {options: jQuery.extend({}, $.fn.checkbox.defaults, $.fn.checkbox.parseOptions(this), opt)});
			}
			bindEvent(this);
		});
	}
	$.fn.checkbox.methods = {
		destroy: function(handle){
			return handle.each(function(){
				destroy(this);
			});
		},
		validate: function(handle){
			return handle.each(function(){
				exec(this);
			});
		},
		validateAll: function(handle){
			var result = true, b;
			handle.each(function(){
				b = exec(this);
				if(result) result = b;
				destroyTip(this);
			}).filter(".checkbox_invalid:visible:eq(0)").focus();
			return result;
		},
		isValid: function(handle){
			return exec(handle[0]);
		},
		destroyTip: function(handle){
			handle.each(function(){
				destroyTip(this);
			});
		}
	};
	$.fn.checkbox.parseOptions = function(el){
		var _el = $(el);
		return {
			required: (_el.hasProp("required") ? (_el.hasProp("required")=="required"||_el.hasProp("required")=="true"||_el.hasProp("required")==true): undefined),
			validType: (_el.attr("validType") || undefined),
			preventHidden: (_el.attr("preventHidden") ? (_el.attr("preventHidden")=="preventHidden"||_el.attr("preventHidden")=="true"||_el.attr("preventHidden")==true) : undefined),
			missingMessage: (_el.attr("missingMessage") || undefined),
			invalidMessage: (_el.attr("invalidMessage") || undefined),
			tipSite: (_el.attr("tipSite") || undefined)	//增加提示框位置属性，默认为右侧，“bottom”表示下方
		};
	}
	$.fn.checkbox.defaults = {
		required: false,
		validType: null,
		preventHidden: false,		//不可见也需要验证
		missingMessage: "该输入项为必输项",
		invalidMessage: null,
		rules:{
			mobile:{
				validator: function(value){
					var regex = /^(1[3458]{1}[0-9]{1}[\d]{8})$/;
					return regex.test(value);
				},
				message: "请输入有效的手机号码"
			},
			email:{
				validator: function(value){
					return /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i.test(value);
				},
				message: "请输入有效的电子邮件地址"
			},
			url:{
				validator: function(value){
					return /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(value);
				},
				message: "请输入有效的URL地址"
			},
			length:{
				validator: function(value, param){
					var len = jQuery.trim(value).length;
					return len >= param[0] && len <= param[1];
				},
				message: "输入内容长度必须介于{0}和{1}之间"
			},
			remote:{
				validator: function(value, param){
					if(2<param.length&&value==param[2]) return true;
					var his = $(this).data("remote_history");
					if(his&&his.value==value) return his.result;
					var queryParam = {};
					queryParam[param[1]] = value;
					var result = jQuery.ajax({
						url: param[0],
						dataType: "text",
						data: queryParam,
						async: false,
						cache: false,
						type: "post"
					}).responseText;
					$(this).data("remote_history", {value:value, result:(result == "true")});
					return result == "true";
				},
				message: "请修正该字段"
			},
			regex:{
				validator: function(value, param){
					var reg = new RegExp(param[0], "g");
					return 1<param.length?{b:reg.test(value),msg:param[1]}:reg.test(value);
				},
				message: "请输入有效的数据"
			},
			equalTo:{
				isNull: true,	//表示即便没有输入值，也要执行验证
				validator: function(value, param){
					return value == $(document.getElementById(param[0])).val();
				},
				message: "两次输入的字符不一致"
			},
			/**
			 * 默认可以是小数或整数
			 * e.g:
			 * 	<input type="text" name="obj.name" class="checkbox" validType="decimals[2]" required="true" maxlength="24"/>
			 * 	表示只能是2位小数或整数
			 * 
			 */
			decimals: {
				validator: function(value, param){
					var fex = "+";
					if(param&&param.length>0)
						fex = "{"+param[0]+"}";
					var reg = new RegExp("^[+-]?((\\d+\\.\\d"+fex+")|\\d*)$","g");
					return reg.test(value);
				},
				message: "请输入有效的小数"
			}
		}
	};
})(jQuery);